// ===========================================================================
// File: P O S T M O N . C P P
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Description:
//
// This sample demonstrates using a URL moniker to submit a request to an HTTP server 
// via the GET or POST methods.
// The key routines include the implementation of IBindStatusCallback
// and the CDownload::DoUpload routine, which creates and binds to the
// URL moniker.
//
// Instructions:
//
//  To use this sample:
//   * build it using the NMAKE command. NMAKE will create POSTMON.EXE.
//   * run POSTMON.EXE. specify the resource to download by passing an
//     URL on the command-line. If no command-line argument is provided
//     the address textbox defaults to "http://<server>/scripts/postmon.asp". 
//     Replace <server> with the name of your own server running IIS 3.0
//  * The program displays a dialog box containing several UI elements

//     - an address textbox for specifying a URL which accepts data
//     - a textbox and combobox for specifying a name and flavor to be 
//       submitted to the sample page POSTMON.ASP. This page was designed to accept
//       this data. Alternatively an editbox is supplied for entering arbitrary data
//       Click the Submit Raw Data checkbox to toggle between modes.
//     - an editbox which displays the download information as it arrives.
//       Once the client posts a request to the server, the server typically responds with 
//       data to be displayed by the client. This is true of POSTMON.ASP.
//     - a progress bar indicating the amount of information that has been downloaded.
//     - a status bar which displays the status message and byte counts which the 
//       client receives through IBindStatusCallback::OnProgress.
//
//  * Press the "Submit" button to begin the download.
//  * Press the "Cancel" button at any time to terminate the download

// Notes from PROGRESS:-
//     If the file exceeds 32KB then only the first 32 KB from the last data
//	   pull will be displayed.  If the pull exceeds 32 KB, then only the first
//     32 KB of the last Read will be displayed.
// 
//
// Sample rewritten for POST by Matt Oshry 20-Feb-1997
// File updated by Jobi George 19-June-1996
// File updated by Ramesha Gopalakrishna 28-June-1996
// File updated by Oliver Wallace 9-July-1996
// Copyright 1995-1997 Microsoft Corporation.  All Rights Reserved.
// ===========================================================================
#include <urlmon.h>
#include <wininet.h>
#include <commctrl.h>
#include <wchar.h>
#include <tchar.h>
#include "resource.h"
#include "statbar.h"
#include "postmon.h"
#include "bsc.h"

#pragma comment(lib, "Urlmon.lib")
#pragma comment(lib, "Wininet.lib")
#pragma comment(lib, "comctl32.lib")

const TCHAR g_cszDefaultURL[] = _T("http://<server>/scripts/postmon.asp");
const TCHAR g_cszPostDataDefault[] = _T("firstname=Matt&flavor=Chocolate");
const TCHAR g_cszDefaultFirstName[] = _T("Matt");
const TCHAR g_cszDefaultFlavor[] = _T("Chocolate");
const DWORD g_dwParamEtcLen = lstrlen(_T("?firstname=&flavor="));

// ===========================================================================
//                           CStatus Implementation
// ===========================================================================

// ---------------------------------------------------------------------------
// %%Function: CStatus::Create
// ---------------------------------------------------------------------------
HRESULT CStatus::Create(CApp* pApp, CStatusBar* pStatusBar, HWND hwndResponse, HWND hwndProgressBar, CStatus** ppStatus)
{
	HRESULT hr;
	CStatus* pStatus;

	if (!ppStatus)
	{
		return E_POINTER;
	}
	
	*ppStatus = NULL;

	pStatus = new CStatus(pApp, pStatusBar, hwndResponse, hwndProgressBar);
	if (!pStatus)
	{
		return E_OUTOFMEMORY;
	}

	hr = pStatus->Init();
	if (FAILED(hr))
	{
		delete pStatus;
		return hr;
	}

	*ppStatus = pStatus;
	return NOERROR;
}

// ---------------------------------------------------------------------------
// %%Function: CDownload::Init
// ---------------------------------------------------------------------------
HRESULT CStatus::Init()
{
	// Clear the contents of the edit box 
	// which displays the response from the server
	SendMessage(m_hwndResponse, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)_T(""));

	// Reset the progress bar
    SendMessage(m_hwndProgressBar, PBM_SETPOS, (WPARAM)0, 0);

	return NOERROR;
}

void CStatus::OnDownloadComplete()
{
	if (m_pApp) m_pApp->EnableUI();
}

// ---------------------------------------------------------------------------
// %%Function: CStatus::AppendResponse
// ---------------------------------------------------------------------------
// Append the incoming data to the response edit box
HRESULT CStatus::AppendResponse(LPCTSTR szResponse)
{
	if (!szResponse)
	{
		return E_INVALIDARG;
	}

	DWORD dStrlength= GetWindowTextLength(m_hwndResponse);
	DWORD dwActuallyRead = lstrlen(szResponse);

	LPTSTR pOldstr = NULL;

	if (dwActuallyRead >= EDIT_BOX_LIMIT)  // Read exceeded Edit box size
	{
		pOldstr= new TCHAR[EDIT_BOX_LIMIT];
		if (!pOldstr)
		{
			return E_OUTOFMEMORY; // was S_FALSE
		}
		// flush the old, keep the new
		lstrcpyn(pOldstr, szResponse, EDIT_BOX_LIMIT-1);
	}
    else if (dStrlength + dwActuallyRead >= EDIT_BOX_LIMIT)
    {
        // This pull exceeded the edit box size.  Only copy the last read.
        pOldstr = new TCHAR[dwActuallyRead+1];
        if (!pOldstr)
        {
            return E_OUTOFMEMORY;  // was S_FALSE
        }
        lstrcpyn(pOldstr, szResponse, dwActuallyRead);
    }
  	else
	{
		// We're in the clear, so just append
		pOldstr= new TCHAR[dStrlength+dwActuallyRead+1];
		if (!pOldstr)
		{
			return E_OUTOFMEMORY;  // was S_FALSE
	 	}

		GetWindowText(m_hwndResponse, pOldstr, (dStrlength+dwActuallyRead+1));
		lstrcat(pOldstr, szResponse);
	}

	SetWindowText(m_hwndResponse, pOldstr);
	delete[] pOldstr;
	
	return NOERROR;
}

// ===========================================================================
//                           CApp Implementation
// ===========================================================================

// ---------------------------------------------------------------------------
// %%Function: CApp::~CApp
// ---------------------------------------------------------------------------
CApp::~CApp()
{
	if (m_pDownload)
	{
		delete m_pDownload;
	}

	if (m_pStatus)
	{
		m_pStatus->Close(); // Zombie the status object so that it doesn't callback into us
		delete m_pStatus;
	}

	if (m_fOleInitialized)
	{
		CoUninitialize();
	}
}

// ---------------------------------------------------------------------------
// %%Function: CApp::Create
// ---------------------------------------------------------------------------
HRESULT CApp::Create(HINSTANCE hinst, LPCTSTR szCmdLine, CApp** ppApp)
{
	HRESULT hr;
	CApp* pApp;

	if (!ppApp)
	{
		return E_POINTER;
	}
	
	*ppApp = NULL;

	pApp = new CApp(hinst, szCmdLine);
	if (!pApp)
	{
		return E_OUTOFMEMORY;
	}

	hr = pApp->Init();
	if (FAILED(hr))
	{
		delete pApp;
		return hr;
	}

	*ppApp = pApp;
	return NOERROR;
}

// ---------------------------------------------------------------------------
// %%Function: CApp::Init
// ---------------------------------------------------------------------------
HRESULT CApp::Init()
{
	HRESULT hr;

	InitCommonControls();

    hr = CoInitialize(NULL);
    if (FAILED(hr))
	{
        return hr;
	}

	m_fOleInitialized = TRUE;

	return hr;
}

// ---------------------------------------------------------------------------
// %%Function: CApp::Run
// ---------------------------------------------------------------------------
int CApp::Run()
{
    return DialogBoxParam(m_hinst, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP,
        (DLGPROC)&DialogProc, (LPARAM)(LPVOID)this);

}

// ---------------------------------------------------------------------------
// %%Function: CApp::OnInitDialog
// ---------------------------------------------------------------------------
HRESULT CApp::OnInitDialog(HWND hwndDlg)
{
	DWORD dwErr = ERROR_SUCCESS;

	if (!hwndDlg)
	{
		return E_INVALIDARG;
	}

	m_hwndFrame = hwndDlg;

	HWND hwndFirstName = GetDlgItem(hwndDlg, IDC_FIRSTNAME);
	HWND hwndFlavor = GetDlgItem(hwndDlg, IDC_FLAVOR);
	HWND hwndPostData = GetDlgItem(hwndDlg, IDC_POSTDATA);

	// POST is the default Action
	SendMessage(GetDlgItem(hwndDlg, IDC_POST), BM_SETCHECK, (WPARAM)BST_CHECKED, 0);

	// Initialize the combobox for flavor selection		
	LRESULT lRes = SendMessage(hwndFlavor, CB_ADDSTRING, 0, (LPARAM)_T("Vanilla"));
	lRes = SendMessage(hwndFlavor, CB_ADDSTRING, 0, (LPARAM)_T("Chocolate"));
	lRes = SendMessage(hwndFlavor, CB_ADDSTRING, 0, (LPARAM)_T("Strawberry"));
	lRes = SendMessage(hwndFlavor, CB_ADDSTRING, 0, (LPARAM)_T("Espresso Chip"));

	TCHAR szUrl[INTERNET_MAX_URL_LENGTH];

	TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH];
	TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH];
	TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
	TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
	TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH];
	TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH];

	URL_COMPONENTS URLComponentsOut;
	ZeroMemory((LPVOID)&URLComponentsOut, sizeof(URLComponentsOut));

	URLComponentsOut.dwStructSize = sizeof(URLComponentsOut);
	URLComponentsOut.lpszScheme = szScheme;         // pointer to scheme name
	URLComponentsOut.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;     // length of scheme name
	URLComponentsOut.lpszHostName = szHostName;       // pointer to host name
	URLComponentsOut.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;   // length of host name
	URLComponentsOut.lpszUserName = szUserName;       // pointer to user name
	URLComponentsOut.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;   // length of user name
	URLComponentsOut.lpszPassword = szPassword;       // pointer to password
	URLComponentsOut.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;   // length of password
	URLComponentsOut.lpszUrlPath = szUrlPath;        // pointer to URL-path
	URLComponentsOut.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;    // length of URL-path
    URLComponentsOut.lpszExtraInfo = szExtraInfo;      // pointer to extra information (e.g. ?foo or #foo)
    URLComponentsOut.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH;  // length of extra information

	DWORD dwFlags = 0;

	if (!InternetCrackUrl(
		m_szCmdLine,
		0,
		dwFlags,
		&URLComponentsOut))
	{
		dwErr = GetLastError();
		SendMessage(GetDlgItem(hwndDlg, IDC_URL), WM_SETTEXT, 0, (LPARAM)g_cszDefaultURL);
		SendMessage(GetDlgItem(hwndDlg, IDC_POSTDATA), WM_SETTEXT, 0, (LPARAM)g_cszPostDataDefault);
		SendMessage(hwndFlavor, CB_SELECTSTRING, (WPARAM) -1, (LPARAM)(LPCSTR)g_cszDefaultFlavor);
		SendMessage(hwndFirstName, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)g_cszDefaultFirstName);
	}
	else
	{ 
		// query string was specified on the command line
		// Copy it into the raw data edit box, and put us in raw submit mode
		if (URLComponentsOut.dwExtraInfoLength > 0)
		{
			LPSTR pszExtraInfo = szExtraInfo+1; // skip over the '?'
			SendMessage(hwndPostData, WM_SETTEXT, 0, (LPARAM)pszExtraInfo);
		}

		URLComponentsOut.lpszExtraInfo = NULL;      // pointer to extra information (e.g. ?foo or #foo)
	    URLComponentsOut.dwExtraInfoLength = 0;  // length of extra information
		DWORD dwUrlLength = INTERNET_MAX_URL_LENGTH;

		SubmitRawData(TRUE);

		if (!InternetCreateUrl( 
			&URLComponentsOut,
			dwFlags,
			szUrl,
			&dwUrlLength))
		{
			dwErr = GetLastError();
		}
		else
		{
			SendMessage(GetDlgItem(hwndDlg, IDC_URL), WM_SETTEXT, 0, (LPARAM)szUrl);
		}
	}

	return NOERROR;
}

// ---------------------------------------------------------------------------
// %%Function: CApp::OnSubmit
// ---------------------------------------------------------------------------
HRESULT CApp::OnSubmit()
{
	HRESULT hr;
    TCHAR szUrl[INTERNET_MAX_URL_LENGTH+1];
	LPTSTR szData = NULL;
	DWORD dwTextLen = 0;

	if (!m_hwndFrame)
	{
		return E_UNEXPECTED;
	}
	
	// Determine the action, GET or POST
	BINDVERB dwAction = (BST_CHECKED == SendMessage(GetDlgItem(m_hwndFrame, IDC_POST), BM_GETCHECK, 0, 0) ? BINDVERB_POST : BINDVERB_GET);

	// Grab the URL path
	int iRetChars = GetWindowText(GetDlgItem(m_hwndFrame, IDC_URL), szUrl, INTERNET_MAX_URL_LENGTH);
	// Must have at least an URL to do anything useful
	if (iRetChars <= 0)
	{
		// User may have cleared the URL box
		m_StatusBar.SetText("Specify URL");
		return E_INVALIDARG;
	}

	{
	// Validate the URL
	MAKE_WIDEPTR_FROMANSI(wszUrl, szUrl);
	LPBINDCTX pbc;
	hr = CreateBindCtx(0, &pbc);
	hr = IsValidURL(pbc, wszUrl, 0);
	pbc->Release();
	}

	if (FAILED(hr))
	{		
		m_StatusBar.SetText("Invalid URL");
		return E_INVALIDARG;
	}

	// Grab the data to submit
	if (ShouldSubmitRawData())
	{
		// Just grab the data from the POST edit box.

		HWND hwndPostData = GetDlgItem(m_hwndFrame, IDC_POSTDATA);
		dwTextLen = SendMessage(hwndPostData, WM_GETTEXTLENGTH, 0, 0);
		if (dwTextLen > 0)
		{
			szData = new TCHAR[dwTextLen+1];
			if (!szData)
			{
				return E_OUTOFMEMORY;
			}
			szData[0] = '\0';

			DWORD cchCopied = SendMessage(hwndPostData, WM_GETTEXT, (WPARAM)dwTextLen+1, (LPARAM)szData);
			if (cchCopied <= 0)
			{
				goto Error;
			}
		}
	}
	else
	{
		// Build the query string based on the name and flavor control values

		HWND hwndFirstName = GetDlgItem(m_hwndFrame, IDC_FIRSTNAME);
		HWND hwndFlavor = GetDlgItem(m_hwndFrame, IDC_FLAVOR);
		dwTextLen = SendMessage(hwndFirstName, WM_GETTEXTLENGTH, 0, 0) + SendMessage(hwndFlavor, WM_GETTEXTLENGTH, 0, 0);
		if (dwTextLen > 0)
		{
			dwTextLen += g_dwParamEtcLen + 1;
			szData = new TCHAR[dwTextLen];
			if (!szData)
			{
				return E_OUTOFMEMORY;
			}

			hr = BuildQueryString(hwndFirstName, hwndFlavor, szData, dwAction);
			if (FAILED(hr))
			{
				return hr;
			}
		}
	}

	if (dwTextLen > INTERNET_MAX_PATH_LENGTH && dwAction == BINDVERB_GET)
	{
		m_StatusBar.SetText(_T("Data exceeds max allowable length. Using POST..."));
		SendMessage(GetDlgItem(m_hwndFrame, IDC_POST), (WPARAM)BM_SETCHECK, BST_CHECKED, 0);
		dwAction = BINDVERB_POST;
	}

	// If multiple downloads were supported, we might 
	// keep each download object in a list of pending downloads
	if (!m_pDownload)
	{
		hr = CDownload::Create(&m_pDownload);
		if (FAILED(hr))
		{
			goto Error;
		}
	}
	else
	{
		m_pStatus->Init();
		m_pDownload->Init();
	}

	if (BINDVERB_GET == dwAction && dwTextLen > 0)
	{
		CombineUrlWithQueryString(szUrl, INTERNET_MAX_URL_LENGTH, szData);
	}

	{
	MAKE_WIDEPTR_FROMANSI(wszUrl, szUrl);

	m_pDownload->DoUpload(m_pStatus, wszUrl, szData, dwAction);
	}

Error:
	if (szData) delete []szData;

	return hr;
}

// ===========================================================================
//                           CDownload Implementation
// ===========================================================================

// ---------------------------------------------------------------------------
// %%Function: CDownload::~CDownload
// ---------------------------------------------------------------------------
CDownload::~CDownload()
{
	Init();
}  // ~CDownload


HRESULT CDownload::Create(/*LPCTSTR szUrl, */ CDownload** ppDownload)
{
	HRESULT hr;
	CDownload* pDownload;

	if (!ppDownload)
	{
		return E_POINTER;
	}
	
	*ppDownload = NULL;

	pDownload = new CDownload();
	if (!pDownload)
	{
		return E_OUTOFMEMORY;
	}

	hr = pDownload->Init(/*szUrl*/);
	if (FAILED(hr))
	{
		delete pDownload;
		return hr;
	}

	*ppDownload = pDownload;
	return NOERROR;

}

// ---------------------------------------------------------------------------
// %%Function: CDownload::Init
// ---------------------------------------------------------------------------
HRESULT CDownload::Init()
{
    if (m_pmk)
	{
        m_pmk->Release();
		m_pmk = NULL;
	}

    if (m_pbc)
	{
        m_pbc->Release();
		m_pbc = NULL;
	}

    if (m_pbsc)
	{
        m_pbsc->Release();
		m_pbsc = NULL;
	}

	return NOERROR;
}

// ---------------------------------------------------------------------------
// %%Function: CDownload::DoUpload
// ---------------------------------------------------------------------------
 HRESULT
CDownload::DoUpload(CStatus* pStatus, LPOLESTR wszUrl, LPCTSTR szData, BINDVERB dwAction)
{
    LPSTREAM pstm = NULL;
    HRESULT hr;

	if (!wszUrl)
	{
		return E_INVALIDARG;
	}

	// When POSTing, URLMON requires that the POST data be provided when URLMON calls
	// the host's implementation of IBindStatusCallback::GetBindInfo
	// If we're POSTing, we pass the data to POSTed on creation of the CBindStatusCallback object.
	// Otherwise, we pass NULL since the data will be supplied as part of the URL passed to CreateURLMoniker below
	hr = CBindStatusCallback::Create(pStatus, (BINDVERB_POST == dwAction ? szData : NULL), dwAction, &m_pbsc);
    if (FAILED(hr))
	{
        goto Error;
    }

    hr = CreateURLMoniker(NULL, wszUrl, &m_pmk);
    if (FAILED(hr))
        goto Error;


    hr = CreateBindCtx(0, &m_pbc);
    if (FAILED(hr))
        goto Error;

    hr = RegisterBindStatusCallback(m_pbc,
            m_pbsc,
            0,
            0L);

    if (FAILED(hr))
	{
        goto Error;
	}

    hr = m_pmk->BindToStorage(m_pbc, 0, IID_IStream, (void**)&pstm);
    if (FAILED(hr))
        goto Error;

    return hr;

Error:
    if (m_pbc != NULL)
        {
        m_pbc->Release();
        m_pbc = NULL;
        }
    if (m_pbsc != NULL)
        {
        m_pbsc->Release();
        m_pbsc = NULL;
        }
    if (m_pmk != NULL)
        {
        m_pmk->Release();
        m_pmk = NULL;
        }
	if (pstm)
		{
		pstm->Release();
		pstm = NULL;
		}
    return hr;
}  // CDownload::DoUpload




// ===========================================================================
//                  User Interface and Initialization Routines
// ===========================================================================

// ---------------------------------------------------------------------------
// %%Function: DialogProc
// ---------------------------------------------------------------------------
 BOOL CALLBACK
DialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	HRESULT hr;
	static CApp* pApp = NULL;

    switch(message)
        {
        case WM_INITDIALOG:
			{
			pApp = (CApp*)(LPVOID)(lParam);
			if (!pApp)
			{
				return FALSE;
			}
			
			HWND hwndResponse = GetDlgItem(hwndDlg, IDC_RESPONSE);
			HWND hwndProgressBar = GetDlgItem(hwndDlg, IDC_PROGRESSBAR);

			// Initialize the status bar
			if (FAILED(pApp->m_StatusBar.Create(hwndDlg)))
			{
				return FALSE;
			}

			pApp->OnInitDialog(hwndDlg);

			// Initialize the status object
			hr = CStatus::Create(pApp, &(pApp->m_StatusBar), hwndResponse, hwndProgressBar, &(pApp->m_pStatus));
			if (FAILED(hr))
			{
				return FALSE;
			}

            break;
			}
        case WM_COMMAND:
            {
            switch (LOWORD(wParam))
                {
                case IDOK: // Submit was pressed
                    {

					HWND hwndOk = GetDlgItem(hwndDlg, IDOK);
					HWND hwndCancel = GetDlgItem(hwndDlg, IDCANCEL);
					HWND hwndUrl = GetDlgItem(hwndDlg, IDC_URL);

					// Disable the UI temporarily
                    EnableWindow(hwndOk, FALSE);
                    EnableWindow(hwndCancel, FALSE);
					EnableWindow(hwndUrl, FALSE);

					hr = pApp->OnSubmit();
					if (E_INVALIDARG == hr)
					{
						EnableWindow(hwndOk, TRUE);
						EnableWindow(hwndUrl, TRUE);
					}
					EnableWindow(hwndCancel, TRUE);

                    break;
                    }

                case IDCANCEL:
                    EndDialog(hwndDlg,0);
                    return 1;

				case IDC_RAW:
					{
					BOOL fSubmitRaw = pApp->ShouldSubmitRawData();
					pApp->SubmitRawData(!fSubmitRaw);
					break;
					}
                }
            break;
            }
		case WM_SIZE:
			{
				int iWidth = LOWORD(lParam);
				int iHeight = HIWORD(lParam);
				CStatusBar* pStatusBar = &(pApp->m_StatusBar);

				if (pStatusBar->GetHWND())
				{
					pStatusBar->OnSize(iWidth, iHeight);
					// Adjust the lParam for the height of the Status Bar
					iHeight -= pStatusBar->GetHeight();
					lParam = MAKELPARAM(iWidth, iHeight);
				}
			}
			break;
        }

    return 0;
}  // DialogProc

// ---------------------------------------------------------------------------
// %%Function: WinMain
// ---------------------------------------------------------------------------
 int WINAPI
WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
{
	CApp* pApp;

	if (FAILED(CApp::Create(hinst, szCmdLine, &pApp)))
	{
		return -1;
	}

	pApp->Run();

	delete pApp;

    return 0;
}  // WinMain


// ---------------------------------------------------------------------------
// %%Function: BuildQueryString
// ---------------------------------------------------------------------------
HRESULT BuildQueryString(HWND hwndFirstName, HWND hwndFlavor, LPSTR szData, BINDVERB dwAction)
{
	#define MAX_NAME 255
	#define MAX_FLAVOR 255

	if (!szData || !hwndFirstName || !hwndFlavor)
	{
		return E_INVALIDARG;
	}

	TCHAR szFirstName[MAX_NAME+1];
	TCHAR szFlavor[MAX_FLAVOR+1];
	int iRetChars;
	iRetChars = GetWindowText(hwndFirstName, szFirstName, MAX_NAME);
	iRetChars = GetWindowText(hwndFlavor, szFlavor, MAX_FLAVOR);
	wsprintf(szData, "%sfirstname=%s&flavor=%s", (BINDVERB_GET == dwAction ? _T("?") : _T("")), szFirstName, szFlavor);

	return NOERROR;
}

// ---------------------------------------------------------------------------
// %%Function: CombineUrlWithQueryString
// ---------------------------------------------------------------------------
HRESULT CombineUrlWithQueryString(LPTSTR szUrl, DWORD dwUrl, LPTSTR szData)
{
	if (!szUrl)
	{
		return E_INVALIDARG;
	}

	if (!szData)
	{
		return S_OK;
	}

	TCHAR szTempUrl[INTERNET_MAX_URL_LENGTH+1];
	TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH];
	TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH];
	TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
	TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
	TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH];
	TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH];

	URL_COMPONENTS URLComponentsOut;
	DWORD dwFlags = 0,
		  dwErr = ERROR_SUCCESS,
		  dwUrlLength = 0;

	ZeroMemory((LPVOID)&URLComponentsOut, sizeof(URLComponentsOut));

	URLComponentsOut.dwStructSize = sizeof(URLComponentsOut);
	URLComponentsOut.lpszScheme = szScheme;         // pointer to scheme name
	URLComponentsOut.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;     // length of scheme name
	URLComponentsOut.lpszHostName = szHostName;       // pointer to host name
	URLComponentsOut.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;   // length of host name
	URLComponentsOut.lpszUserName = szUserName;       // pointer to user name
	URLComponentsOut.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;   // length of user name
	URLComponentsOut.lpszPassword = szPassword;       // pointer to password
	URLComponentsOut.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;   // length of password
	URLComponentsOut.lpszUrlPath = szUrlPath;        // pointer to URL-path
	URLComponentsOut.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;    // length of URL-path
    URLComponentsOut.lpszExtraInfo = szExtraInfo;      // pointer to extra information (e.g. ?foo or #foo)
    URLComponentsOut.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH;  // length of extra information

	// break the URL apart
	if (!InternetCrackUrl(
		szUrl,
		0,
		dwFlags,
		&URLComponentsOut))
	{
		dwErr = GetLastError();
		return HRESULT_FROM_WIN32(dwErr);
	}

	// discard any extra info that's already attached to the path.
	wsprintf(szExtraInfo, "%s%s", ('?' == szData[0] ? _T("") : "?"), szData);
	URLComponentsOut.dwExtraInfoLength = lstrlen(szExtraInfo);  // length of extra information		
		
	dwUrlLength = INTERNET_MAX_URL_LENGTH;

	// now put it back together again with the query string attached
	if (!InternetCreateUrl( 
		&URLComponentsOut,
		dwFlags,
		szTempUrl,
		&dwUrlLength))
	{
		dwErr = GetLastError();
		return HRESULT_FROM_WIN32(dwErr);
	}
	else
	{
		dwFlags = ICU_ENCODE_SPACES_ONLY;
		dwUrlLength = dwUrl;
		szUrl[0] = '\0';

		// turn those spaces into legal characters (e.g "Mocha Chip" -> "Mocha+Chip"
		if (!InternetCanonicalizeUrl(
			szTempUrl,
			szUrl,
			&dwUrl,
			dwFlags))
		{
			dwErr = GetLastError();
			//return dwErr;
		}
	}

	return NOERROR;
}

// EOF =======================================================================

